home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 26 / AACD 26.iso / AACD / Online / x3270 / unix_files / telnet.c < prev    next >
Encoding:
C/C++ Source or Header  |  2009-02-26  |  56.2 KB  |  2,666 lines

  1. /*
  2.  * Modifications Copyright 1993, 1994, 1995, 1999, 2000 by Paul Mattes.
  3.  * Original X11 Port Copyright 1990 by Jeff Sparkes.
  4.  *  Permission to use, copy, modify, and distribute this software and its
  5.  *  documentation for any purpose and without fee is hereby granted,
  6.  *  provided that the above copyright notice appear in all copies and that
  7.  *  both that copyright notice and this permission notice appear in
  8.  *  supporting documentation.
  9.  *
  10.  * Copyright 1989 by Georgia Tech Research Corporation, Atlanta, GA 30332.
  11.  *  All Rights Reserved.  GTRC hereby grants public use of this software.
  12.  *  Derivative works based on this software must incorporate this copyright
  13.  *  notice.
  14.  */
  15.  
  16. /*
  17.  *    telnet.c
  18.  *        This module initializes and manages a telnet socket to
  19.  *        the given IBM host.
  20.  */
  21.  
  22. #include "globals.h"
  23. #include <sys/socket.h>
  24. #include <sys/ioctl.h>
  25. #include <netinet/in.h>
  26. #define TELCMDS 1
  27. #define TELOPTS 1
  28. #include "arpa_telnet.h"
  29. #include <arpa/inet.h>
  30. #include <errno.h>
  31. #include <fcntl.h>
  32. #include <netdb.h>
  33. #include <stdarg.h>
  34. #include "tn3270e.h"
  35.  
  36. #include "appres.h"
  37.  
  38. #include "ansic.h"
  39. #include "ctlrc.h"
  40. #include "hostc.h"
  41. #include "kybdc.h"
  42. #include "macrosc.h"
  43. #include "popupsc.h"
  44. #include "statusc.h"
  45. #include "telnetc.h"
  46. #include "trace_dsc.h"
  47. #include "utilc.h"
  48. #include "xioc.h"
  49.  
  50. #if !defined(TELOPT_NAWS) /*[*/
  51. #define TELOPT_NAWS    31
  52. #endif /*]*/
  53.  
  54. #define BUFSZ        4096
  55. #define TRACELINE    72
  56.  
  57. #define N_OPTS        256
  58.  
  59. /* Globals */
  60. char        *hostname = CN;
  61. time_t          ns_time;
  62. int             ns_brcvd;
  63. int             ns_rrcvd;
  64. int             ns_bsent;
  65. int             ns_rsent;
  66. unsigned char  *obuf;        /* 3270 output buffer */
  67. unsigned char  *obptr = (unsigned char *) NULL;
  68. int             linemode = 1;
  69. #if defined(LOCAL_PROCESS) /*[*/
  70. Boolean        local_process = False;
  71. #endif /*]*/
  72. char           *termtype;
  73.  
  74. /* Externals */
  75. extern struct timeval ds_ts;
  76.  
  77. /* Statics */
  78. static int      sock = -1;    /* active socket */
  79. static unsigned char myopts[N_OPTS], hisopts[N_OPTS];
  80.             /* telnet option flags */
  81. static unsigned char *ibuf = (unsigned char *) NULL;
  82.             /* 3270 input buffer */
  83. static unsigned char *ibptr;
  84. static int      ibuf_size = 0;    /* size of ibuf */
  85. static unsigned char *obuf_base = (unsigned char *)NULL;
  86. static int    obuf_size = 0;
  87. static unsigned char *netrbuf = (unsigned char *)NULL;
  88.             /* network input buffer */
  89. static unsigned char *sbbuf = (unsigned char *)NULL;
  90.             /* telnet sub-option buffer */
  91. static unsigned char *sbptr;
  92. static unsigned char telnet_state;
  93. static int      syncing;
  94. static char     ttype_tmpval[13];
  95.  
  96. #if defined(X3270_TN3270E) /*[*/
  97. static unsigned long e_funcs;    /* negotiated TN3270E functions */
  98. #define E_OPT(n)    (1 << (n))
  99. static unsigned short e_xmit_seq; /* transmit sequence number */
  100. static int response_required;
  101. #endif /*]*/
  102.  
  103. #if defined(X3270_ANSI) /*[*/
  104. static int      ansi_data = 0;
  105. static unsigned char *lbuf = (unsigned char *)NULL;
  106.             /* line-mode input buffer */
  107. static unsigned char *lbptr;
  108. static int      lnext = 0;
  109. static int      backslashed = 0;
  110. static int      t_valid = 0;
  111. static char     vintr;
  112. static char     vquit;
  113. static char     verase;
  114. static char     vkill;
  115. static char     veof;
  116. static char     vwerase;
  117. static char     vrprnt;
  118. static char     vlnext;
  119. #endif /*]*/
  120.  
  121. static int    tn3270e_negotiated = 0;
  122. static enum { E_NONE, E_3270, E_NVT, E_SSCP } tn3270e_submode = E_NONE;
  123. static int    tn3270e_bound = 0;
  124. static char    **lus = (char **)NULL;
  125. static char    **curr_lu = (char **)NULL;
  126. static char    *try_lu = CN;
  127.  
  128. static int telnet_fsm(unsigned char c);
  129. static void net_rawout(unsigned const char *buf, int len);
  130. static void check_in3270(void);
  131. static void store3270in(unsigned char c);
  132. static void check_linemode(Boolean init);
  133. static int non_blocking(Boolean on);
  134. static void net_connected(void);
  135. #if defined(X3270_TN3270E) /*[*/
  136. static int tn3270e_negotiate(void);
  137. #endif /*]*/
  138. static int process_eor(void);
  139. #if defined(X3270_TN3270E) /*[*/
  140. static const char *tn3270e_function_names(const unsigned char *, int);
  141. static void tn3270e_subneg_send(unsigned char, unsigned long);
  142. static unsigned long tn3270e_fdecode(const unsigned char *, int);
  143. static void tn3270e_ack(void);
  144. static void tn3270e_nak(enum pds);
  145. #endif /*]*/
  146.  
  147. #if defined(X3270_ANSI) /*[*/
  148. static void do_data(char c);
  149. static void do_intr(char c);
  150. static void do_quit(char c);
  151. static void do_cerase(char c);
  152. static void do_werase(char c);
  153. static void do_kill(char c);
  154. static void do_rprnt(char c);
  155. static void do_eof(char c);
  156. static void do_eol(char c);
  157. static void do_lnext(char c);
  158. static char parse_ctlchar(char *s);
  159. static void cooked_init(void);
  160. #endif /*]*/
  161.  
  162. #if defined(X3270_TRACE) /*[*/
  163. static void trace_str(const char *s);
  164. static void vtrace_str(const char *fmt, ...);
  165. static const char *cmd(unsigned char c);
  166. static const char *opt(unsigned char c);
  167. static const char *nnn(int c);
  168. #else /*][*/
  169. #define trace_str 0 &&
  170. #define vtrace_str 0 &&
  171. #define cmd(x) 0
  172. #define opt(x) 0
  173. #define nnn(x) 0
  174. #endif /*]*/
  175.  
  176. /* telnet states */
  177. #define TNS_DATA    0    /* receiving data */
  178. #define TNS_IAC        1    /* got an IAC */
  179. #define TNS_WILL    2    /* got an IAC WILL */
  180. #define TNS_WONT    3    /* got an IAC WONT */
  181. #define TNS_DO        4    /* got an IAC DO */
  182. #define TNS_DONT    5    /* got an IAC DONT */
  183. #define TNS_SB        6    /* got an IAC SB */
  184. #define TNS_SB_IAC    7    /* got an IAC after an IAC SB */
  185.  
  186. /* telnet predefined messages */
  187. static unsigned char    do_opt[]    = { 
  188.     IAC, DO, '_' };
  189. static unsigned char    dont_opt[]    = { 
  190.     IAC, DONT, '_' };
  191. static unsigned char    will_opt[]    = { 
  192.     IAC, WILL, '_' };
  193. static unsigned char    wont_opt[]    = { 
  194.     IAC, WONT, '_' };
  195. #if defined(X3270_TN3270E) /*[*/
  196. static unsigned char    functions_req[] = {
  197.     IAC, SB, TELOPT_TN3270E, TN3270E_OP_FUNCTIONS };
  198. #endif /*]*/
  199.  
  200. static const char *telquals[2] = { "IS", "SEND" };
  201. #if defined(X3270_TN3270E) /*[*/
  202. static const char *reason_code[8] = { "CONN-PARTNER", "DEVICE-IN-USE",
  203.     "INV-ASSOCIATE", "INV-NAME", "INV-DEVICE-TYPE", "TYPE-NAME-ERROR",
  204.     "UNKNOWN-ERROR", "UNSUPPORTED-REQ" };
  205. #define rsn(n)    (((n) <= TN3270E_REASON_UNSUPPORTED_REQ) ? \
  206.             reason_code[(n)] : "??")
  207. static const char *function_name[5] = { "BIND-IMAGE", "DATA-STREAM-CTL",
  208.     "RESPONSES", "SCS-CTL-CODES", "SYSREQ" };
  209. #define fnn(n)    (((n) <= TN3270E_FUNC_SYSREQ) ? \
  210.             function_name[(n)] : "??")
  211. static const char *data_type[9] = { "3270-DATA", "SCS-DATA", "RESPONSE",
  212.     "BIND-IMAGE", "UNBIND", "NVT-DATA", "REQUEST", "SSCP-LU-DATA",
  213.     "PRINT-EOJ" };
  214. #define e_dt(n)    (((n) <= TN3270E_DT_PRINT_EOJ) ? \
  215.             data_type[(n)] : "??")
  216. static const char *req_flag[1] = { " ERR-COND-CLEARED" };
  217. #define e_rq(fn, n) (((fn) == TN3270E_DT_REQUEST) ? \
  218.             (((n) <= TN3270E_RQF_ERR_COND_CLEARED) ? \
  219.             req_flag[(n)] : " ??") : "")
  220. static const char *hrsp_flag[3] = { "NO-RESPONSE", "ERROR-RESPONSE",
  221.     "ALWAYS-RESPONSE" };
  222. #define e_hrsp(n) (((n) <= TN3270E_RSF_ALWAYS_RESPONSE) ? \
  223.             hrsp_flag[(n)] : "??")
  224. static const char *trsp_flag[2] = { "POSITIVE-RESPONSE", "NEGATIVE-RESPONSE" };
  225. #define e_trsp(n) (((n) <= TN3270E_RSF_NEGATIVE_RESPONSE) ? \
  226.             trsp_flag[(n)] : "??")
  227. #define e_rsp(fn, n) (((fn) == TN3270E_DT_RESPONSE) ? e_trsp(n) : e_hrsp(n))
  228. #endif /*]*/
  229.  
  230.  
  231. /*
  232.  * net_connect
  233.  *    Establish a telnet socket to the given host passed as an argument.
  234.  *    Called only once and is responsible for setting up the telnet
  235.  *    variables.  Returns the file descriptor of the connected socket.
  236.  */
  237. int
  238. net_connect(const char *host, char *portname, Boolean ls, Boolean *pending)
  239. {
  240.     struct servent    *sp;
  241.     struct hostent    *hp;
  242.     unsigned short        port;
  243.     char                passthru_haddr[8];
  244.     int            passthru_len = 0;
  245.     unsigned short        passthru_port = 0;
  246.     struct sockaddr_in    haddr;
  247.     int            on = 1;
  248. #if defined(OMTU) /*[*/
  249.     int            mtu = OMTU;
  250. #endif /*]*/
  251.  
  252. #    define close_fail    { (void) close(sock); sock = -1; return -1; }
  253.  
  254.     if (netrbuf == (unsigned char *)NULL)
  255.         netrbuf = (unsigned char *)Malloc(BUFSZ);
  256.  
  257. #if defined(X3270_ANSI) /*[*/
  258.     if (!t_valid) {
  259.         vintr   = parse_ctlchar(appres.intr);
  260.         vquit   = parse_ctlchar(appres.quit);
  261.         verase  = parse_ctlchar(appres.erase);
  262.         vkill   = parse_ctlchar(appres.kill);
  263.         veof    = parse_ctlchar(appres.eof);
  264.         vwerase = parse_ctlchar(appres.werase);
  265.         vrprnt  = parse_ctlchar(appres.rprnt);
  266.         vlnext  = parse_ctlchar(appres.lnext);
  267.         t_valid = 1;
  268.     }
  269. #endif /*]*/
  270.  
  271.     *pending = False;
  272.  
  273.     if (hostname)
  274.         Free(hostname);
  275.     hostname = NewString(host);
  276.  
  277.     /* get the passthru host and port number */
  278.     if (passthru_host) {
  279.         const char *hn;
  280.  
  281.         hn = getenv("INTERNET_HOST");
  282.         if (hn == CN)
  283.             hn = "internet-gateway";
  284.  
  285.         hp = gethostbyname(hn);
  286.         if (hp == (struct hostent *) 0) {
  287.             popup_an_error("Unknown passthru host: %s", hn);
  288.             return -1;
  289.         }
  290.         (void) memmove(passthru_haddr, hp->h_addr, hp->h_length);
  291.         passthru_len = hp->h_length;
  292.  
  293.         sp = getservbyname("telnet-passthru","tcp");
  294.         if (sp != (struct servent *)NULL)
  295.             passthru_port = sp->s_port;
  296.         else
  297.             passthru_port = htons(3514);
  298.     }
  299.  
  300.     /* get the port number */
  301.     port = (unsigned short) atoi(portname);
  302.     if (port)
  303.         port = htons(port);
  304.     else {
  305.         if (!(sp = getservbyname(portname, "tcp"))) {
  306.             popup_an_error("Unknown port number or service: %s",
  307.                 portname);
  308.             return -1;
  309.         }
  310.         port = sp->s_port;
  311.     }
  312.     current_port = ntohs(port);
  313.  
  314.  
  315.     /* fill in the socket address of the given host */
  316.     (void) memset((char *) &haddr, 0, sizeof(haddr));
  317.     if (passthru_host) {
  318.         haddr.sin_family = AF_INET;
  319.         (void) memmove(&haddr.sin_addr, passthru_haddr, passthru_len);
  320.         haddr.sin_port = passthru_port;
  321.     } else {
  322. #if defined(LOCAL_PROCESS) /*[*/
  323.         if (ls) {
  324.             local_process = True;
  325.         } else {
  326.             local_process = False;
  327. #endif /*]*/
  328.             hp = gethostbyname(host);
  329.             if (hp == (struct hostent *) 0) {
  330.                 haddr.sin_family = AF_INET;
  331.                 haddr.sin_addr.s_addr = inet_addr(host);
  332.                 if (haddr.sin_addr.s_addr == (unsigned long)-1) {
  333.                     popup_an_error("Unknown host:\n%s",
  334.                         hostname);
  335.                     return -1;
  336.                 }
  337.             }
  338.             else {
  339.                 haddr.sin_family = hp->h_addrtype;
  340.                 (void) memmove(&haddr.sin_addr, hp->h_addr,
  341.                            hp->h_length);
  342.             }
  343.             haddr.sin_port = port;
  344. #if defined(LOCAL_PROCESS) /*[*/
  345.         }
  346. #endif /*]*/
  347.  
  348.     }
  349.  
  350. #if defined(LOCAL_PROCESS) /*[*/
  351.     if (local_process) {
  352.         int amaster;
  353.         struct winsize w;
  354.  
  355.         w.ws_row = maxROWS;
  356.         w.ws_col = maxCOLS;
  357.         w.ws_xpixel = 0;
  358.         w.ws_ypixel = 0;
  359.  
  360.         switch (forkpty(&amaster, NULL, NULL, &w)) {
  361.             case -1:    /* failed */
  362.             popup_an_errno(errno, "forkpty");
  363.             close_fail;
  364.             case 0:    /* child */
  365.             putenv("TERM=xterm");
  366.             if (strchr(host, ' ') != CN) {
  367.                 (void) execlp("/bin/sh", "sh", "-c", host,
  368.                     NULL);
  369.             } else {
  370.                 char *arg1;
  371.  
  372.                 arg1 = strrchr(host, '/');
  373.                 (void) execlp(host,
  374.                     (arg1 == CN) ? host : arg1 + 1,
  375.                     NULL);
  376.             }
  377.             perror(host);
  378.             _exit(1);
  379.             break;
  380.             default:    /* parent */
  381.             sock = amaster;
  382.             (void) fcntl(sock, F_SETFD, 1);
  383.             net_connected();
  384.             host_in3270(CONNECTED_ANSI);
  385.             break;
  386.         }
  387.     } else {
  388. #endif /*]*/
  389.         /* create the socket */
  390.         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  391.             popup_an_errno(errno, "socket");
  392.             return -1;
  393.         }
  394.  
  395.         /* set options for inline out-of-band data and keepalives */
  396.         if (setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, (char *)&on,
  397.                 sizeof(on)) < 0) {
  398.             popup_an_errno(errno, "setsockopt(SO_OOBINLINE)");
  399.             close_fail;
  400.         }
  401.         if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
  402.                 sizeof(on)) < 0) {
  403.             popup_an_errno(errno, "setsockopt(SO_KEEPALIVE)");
  404.             close_fail;
  405.         }
  406. #if defined(OMTU) /*[*/
  407.         if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&mtu,
  408.                 sizeof(mtu)) < 0) {
  409.             popup_an_errno(errno, "setsockopt(SO_SNDBUF)");
  410.             close_fail;
  411.         }
  412. #endif /*]*/
  413.  
  414.         /* set the socket to be non-delaying */
  415.         if (non_blocking(True) < 0)
  416.             close_fail;
  417.  
  418.         /* don't share the socket with our children */
  419.         (void) fcntl(sock, F_SETFD, 1);
  420.  
  421.         /* connect */
  422.         if (connect(sock, (struct sockaddr *) &haddr, sizeof(haddr)) == -1) {
  423.             if (errno == EWOULDBLOCK
  424. #if defined(EINPROGRESS) /*[*/
  425.                 || errno == EINPROGRESS
  426. #endif /*]*/
  427.                            ) {
  428.                 trace_str("Connection pending.\n");
  429.                 *pending = True;
  430.             } else {
  431.                 popup_an_errno(errno, "Connect to %s, port %d",
  432.                     hostname, current_port);
  433.                 close_fail;
  434.             }
  435.         } else {
  436.             if (non_blocking(False) < 0)
  437.                 close_fail;
  438.             net_connected();
  439.         }
  440. #if defined(LOCAL_PROCESS) /*[*/
  441.     }
  442. #endif /*]*/
  443.  
  444.     /* set up temporary termtype */
  445.     if (appres.termname == CN && std_ds_host) {
  446.         (void) sprintf(ttype_tmpval, "IBM-327%c-%d",
  447.             appres.m3279 ? '9' : '8', model_num);
  448.         termtype = ttype_tmpval;
  449.     }
  450.  
  451.     /* all done */
  452.     return sock;
  453. }
  454. #undef close_fail
  455.  
  456. /* Set up the LU list. */
  457. static void
  458. setup_lus(void)
  459. {
  460.     char *lu;
  461.     char *comma;
  462.     int n_lus = 1;
  463.     int i;
  464.  
  465.     connected_lu = CN;
  466.     connected_type = CN;
  467.  
  468.     if (!luname[0]) {
  469.         if (lus) {
  470.             Free(lus);
  471.             lus = (char **)NULL;
  472.         }
  473.         curr_lu = (char **)NULL;
  474.         try_lu = CN;
  475.         return;
  476.     }
  477.  
  478.     /*
  479.      * Count the commas in the LU name.  That plus one is the
  480.      * number of LUs to try. 
  481.      */
  482.     lu = luname;
  483.     while ((comma = strchr(lu, ',')) != CN) {
  484.         n_lus++;
  485.         lu++;
  486.     }
  487.  
  488.     /*
  489.      * Allocate enough memory to construct an argv[] array for
  490.      * the LUs.
  491.      */
  492.     lus = (char **)Malloc((n_lus+1) * sizeof(char *) + strlen(luname) + 1);
  493.  
  494.     /* Copy each LU into the array. */
  495.     lu = (char *)(lus + n_lus + 1);
  496.     (void) strcpy(lu, luname);
  497.     i = 0;
  498.     do {
  499.         lus[i++] = lu;
  500.         comma = strchr(lu, ',');
  501.         if (comma != CN) {
  502.             *comma = '\0';
  503.             lu = comma + 1;
  504.         }
  505.     } while (comma != CN);
  506.     lus[i] = CN;
  507.     curr_lu = lus;
  508.     try_lu = *curr_lu;
  509. }
  510.  
  511. static void
  512. net_connected(void)
  513. {
  514.     vtrace_str("Connected to %s, port %u.\n", hostname, current_port);
  515.  
  516.     /* set up telnet options */
  517.     (void) memset((char *) myopts, 0, sizeof(myopts));
  518.     (void) memset((char *) hisopts, 0, sizeof(hisopts));
  519. #if defined(X3270_TN3270E) /*[*/
  520.     e_funcs = E_OPT(TN3270E_FUNC_BIND_IMAGE) |
  521.           E_OPT(TN3270E_FUNC_RESPONSES) |
  522.           E_OPT(TN3270E_FUNC_SYSREQ);
  523.     e_xmit_seq = 0;
  524.     response_required = TN3270E_RSF_NO_RESPONSE;
  525. #endif /*]*/
  526.     telnet_state = TNS_DATA;
  527.     ibptr = ibuf;
  528.  
  529.     /* clear statistics and flags */
  530.     (void) time(&ns_time);
  531.     ns_brcvd = 0;
  532.     ns_rrcvd = 0;
  533.     ns_bsent = 0;
  534.     ns_rsent = 0;
  535.     syncing = 0;
  536.     tn3270e_negotiated = 0;
  537.     tn3270e_submode = E_NONE;
  538.     tn3270e_bound = 0;
  539.  
  540.     setup_lus();
  541.  
  542.     check_linemode(True);
  543.  
  544.     /* write out the passthru hostname and port nubmer */
  545.     if (passthru_host) {
  546.         char *buf;
  547.  
  548.         buf = Malloc(strlen(hostname) + 32);
  549.         (void) sprintf(buf, "%s %d\r\n", hostname, current_port);
  550.         (void) write(sock, buf, strlen(buf));
  551.         Free(buf);
  552.     }
  553. }
  554.  
  555. /*
  556.  * net_disconnect
  557.  *    Shut down the socket.
  558.  */
  559. void
  560. net_disconnect(void)
  561. {
  562.     if (CONNECTED)
  563.         (void) shutdown(sock, 2);
  564.     (void) close(sock);
  565.     sock = -1;
  566.     trace_str("SENT disconnect\n");
  567.  
  568.     /* Restore terminal type to its default. */
  569.     if (appres.termname == CN)
  570.         termtype = full_model_name;
  571. }
  572.  
  573.  
  574. /*
  575.  * net_input
  576.  *    Called by the toolkit whenever there is input available on the
  577.  *    socket.  Reads the data, processes the special telnet commands
  578.  *    and calls process_ds to process the 3270 data stream.
  579.  */
  580. void
  581. net_input(void)
  582. {
  583.     register unsigned char    *cp;
  584.     int    nr;
  585.  
  586. #if defined(X3270_ANSI) /*[*/
  587.     ansi_data = 0;
  588. #endif /*]*/
  589.  
  590.     nr = read(sock, (char *) netrbuf, BUFSZ);
  591.     if (nr < 0) {
  592.         if (errno == EWOULDBLOCK)
  593.             return;
  594.         if (HALF_CONNECTED && errno == EAGAIN) {
  595.             if (non_blocking(False) < 0) {
  596.                 host_disconnect(True);
  597.                 return;
  598.             }
  599.             host_connected();
  600.             net_connected();
  601.             return;
  602.         }
  603.         vtrace_str("RCVD socket error %d\n", errno);
  604.         if (HALF_CONNECTED)
  605.             popup_an_errno(errno, "Connect to %s, port %d",
  606.                 hostname, current_port);
  607.         else if (errno != ECONNRESET)
  608.             popup_an_errno(errno, "Socket read");
  609.         host_disconnect(True);
  610.         return;
  611.     } else if (nr == 0) {
  612.         /* Host disconnected. */
  613.         trace_str("RCVD disconnect\n");
  614.         host_disconnect(False);
  615.         return;
  616.     }
  617.  
  618.     /* Process the data. */
  619.  
  620.     if (HALF_CONNECTED) {
  621.         if (non_blocking(False) < 0) {
  622.             host_disconnect(True);
  623.             return;
  624.         }
  625.         host_connected();
  626.         net_connected();
  627.     }
  628.  
  629. #if defined(X3270_TRACE) /*[*/
  630.     trace_netdata('<', netrbuf, nr);
  631. #endif /*]*/
  632.  
  633.     ns_brcvd += nr;
  634.     for (cp = netrbuf; cp < (netrbuf + nr); cp++) {
  635. #if defined(LOCAL_PROCESS) /*[*/
  636.         if (local_process) {
  637.             /* More to do here, probably. */
  638.             if (IN_NEITHER) {    /* now can assume ANSI mode */
  639.                 host_in3270(CONNECTED_ANSI);
  640.                 hisopts[TELOPT_ECHO] = 1;
  641.                 check_linemode(False);
  642.                 kybdlock_clr(KL_AWAITING_FIRST, "telnet_fsm");
  643.                 status_reset();
  644.                 ps_process();
  645.             }
  646.             ansi_process((unsigned int) *cp);
  647.         } else {
  648. #endif /*]*/
  649.             if (telnet_fsm(*cp)) {
  650.                 host_disconnect(True);
  651.                 return;
  652.             }
  653. #if defined(LOCAL_PROCESS) /*[*/
  654.         }
  655. #endif /*]*/
  656.     }
  657.  
  658. #if defined(X3270_ANSI) /*[*/
  659.     if (ansi_data) {
  660.         trace_str("\n");
  661.         ansi_data = 0;
  662.     }
  663. #endif /*]*/
  664. }
  665.  
  666.  
  667. /*
  668.  * set16
  669.  *    Put a 16-bit value in a buffer.
  670.  *    Returns the number of bytes required.
  671.  */
  672. static int
  673. set16(char *buf, int n)
  674. {
  675.     char *b0 = buf;
  676.  
  677.     n %= 256 * 256;
  678.     if ((n / 256) == IAC)
  679.         *(unsigned char *)buf++ = IAC;
  680.     *buf++ = (n / 256);
  681.     n %= 256;
  682.     if (n == IAC)
  683.         *(unsigned char *)buf++ = IAC;
  684.     *buf++ = n;
  685.     return buf - b0;
  686. }
  687.  
  688. /*
  689.  * send_naws
  690.  *    Send a Telnet window size sub-option negotation.
  691.  */
  692. static void
  693. send_naws(void)
  694. {
  695.     char naws_msg[14];
  696.     int naws_len = 0;
  697.  
  698.     (void) sprintf(naws_msg, "%c%c%c", IAC, SB, TELOPT_NAWS);
  699.     naws_len += 3;
  700.     naws_len += set16(naws_msg + naws_len, maxCOLS);
  701.     naws_len += set16(naws_msg + naws_len, maxROWS);
  702.     (void) sprintf(naws_msg + naws_len, "%c%c", IAC, SE);
  703.     naws_len += 2;
  704.     net_rawout((unsigned char *)naws_msg, naws_len);
  705.     vtrace_str("SENT %s NAWS %d %d %s\n", cmd(SB), maxCOLS,
  706.         maxROWS, cmd(SE));
  707. }
  708.  
  709.  
  710.  
  711. /* Advance 'try_lu' to the next desired LU name. */
  712. static void
  713. next_lu(void)
  714. {
  715.     if (curr_lu != (char **)NULL && (try_lu = *++curr_lu) == CN)
  716.         curr_lu = (char **)NULL;
  717. }
  718.  
  719. /*
  720.  * telnet_fsm
  721.  *    Telnet finite-state machine.
  722.  *    Returns 0 for okay, -1 for errors.
  723.  */
  724. static int
  725. telnet_fsm(unsigned char c)
  726. {
  727.     char    *see_chr;
  728.     int    sl;
  729.  
  730.     switch (telnet_state) {
  731.         case TNS_DATA:    /* normal data processing */
  732.         if (c == IAC) {    /* got a telnet command */
  733.             telnet_state = TNS_IAC;
  734. #if defined(X3270_ANSI) /*[*/
  735.             if (ansi_data) {
  736.                 trace_str("\n");
  737.                 ansi_data = 0;
  738.             }
  739. #endif /*]*/
  740.             break;
  741.         }
  742.         if (IN_NEITHER) {    /* now can assume ANSI mode */
  743.             host_in3270(CONNECTED_ANSI);
  744. #if defined(X3270_ANSI)/*[*/
  745.             if (linemode)
  746.                 cooked_init();
  747. #endif /*]*/
  748.             kybdlock_clr(KL_AWAITING_FIRST, "telnet_fsm");
  749.             status_reset();
  750.             ps_process();
  751.         }
  752.         if (IN_ANSI && !IN_E) {
  753. #if defined(X3270_ANSI) /*[*/
  754.             if (!ansi_data) {
  755.                 trace_str("<.. ");
  756.                 ansi_data = 4;
  757.             }
  758.             see_chr = ctl_see((int) c);
  759.             ansi_data += (sl = strlen(see_chr));
  760.             if (ansi_data >= TRACELINE) {
  761.                 trace_str(" ...\n... ");
  762.                 ansi_data = 4 + sl;
  763.             }
  764.             trace_str(see_chr);
  765.             if (!syncing) {
  766.                 ansi_process((unsigned int) c);
  767.                 sms_store(c);
  768.             }
  769. #endif /*]*/
  770.         } else {
  771.             store3270in(c);
  772.         }
  773.         break;
  774.         case TNS_IAC:    /* process a telnet command */
  775.         if (c != EOR && c != IAC) {
  776.             vtrace_str("RCVD %s ", cmd(c));
  777.         }
  778.         switch (c) {
  779.             case IAC:    /* escaped IAC, insert it */
  780.             if (IN_ANSI && !IN_E) {
  781. #if defined(X3270_ANSI) /*[*/
  782.                 if (!ansi_data) {
  783.                     trace_str("<.. ");
  784.                     ansi_data = 4;
  785.                 }
  786.                 see_chr = ctl_see((int) c);
  787.                 ansi_data += (sl = strlen(see_chr));
  788.                 if (ansi_data >= TRACELINE) {
  789.                     trace_str(" ...\n ...");
  790.                     ansi_data = 4 + sl;
  791.                 }
  792.                 trace_str(see_chr);
  793.                 ansi_process((unsigned int) c);
  794.                 sms_store(c);
  795. #endif /*]*/
  796.             } else
  797.                 store3270in(c);
  798.             telnet_state = TNS_DATA;
  799.             break;
  800.             case EOR:    /* eor, process accumulated input */
  801.             if (IN_3270 || (IN_E && tn3270e_negotiated)) {
  802.                 ns_rrcvd++;
  803.                 if (process_eor())
  804.                     return -1;
  805.             } else
  806.                 Warning("EOR received when not in 3270 mode, "
  807.                     "ignored.");
  808.             trace_str("RCVD EOR\n");
  809.             ibptr = ibuf;
  810.             telnet_state = TNS_DATA;
  811.             break;
  812.             case WILL:
  813.             telnet_state = TNS_WILL;
  814.             break;
  815.             case WONT:
  816.             telnet_state = TNS_WONT;
  817.             break;
  818.             case DO:
  819.             telnet_state = TNS_DO;
  820.             break;
  821.             case DONT:
  822.             telnet_state = TNS_DONT;
  823.             break;
  824.             case SB:
  825.             telnet_state = TNS_SB;
  826.             if (sbbuf == (unsigned char *)NULL)
  827.                 sbbuf = (unsigned char *)Malloc(1024);
  828.             sbptr = sbbuf;
  829.             break;
  830.             case DM:
  831.             trace_str("\n");
  832.             if (syncing) {
  833.                 syncing = 0;
  834.                 x_except_on(sock);
  835.             }
  836.             telnet_state = TNS_DATA;
  837.             break;
  838.             case GA:
  839.             case NOP:
  840.             trace_str("\n");
  841.             telnet_state = TNS_DATA;
  842.             break;
  843.             default:
  844.             trace_str("???\n");
  845.             telnet_state = TNS_DATA;
  846.             break;
  847.         }
  848.         break;
  849.         case TNS_WILL:    /* telnet WILL DO OPTION command */
  850.         vtrace_str("%s\n", opt(c));
  851.         switch (c) {
  852.             case TELOPT_SGA:
  853.             case TELOPT_BINARY:
  854.             case TELOPT_EOR:
  855.             case TELOPT_TTYPE:
  856.             case TELOPT_ECHO:
  857. #if defined(X3270_TN3270E) /*[*/
  858.             case TELOPT_TN3270E:
  859. #endif /*]*/
  860.             if (c != TELOPT_TN3270E || !non_tn3270e_host) {
  861.                 if (!hisopts[c]) {
  862.                     hisopts[c] = 1;
  863.                     do_opt[2] = c;
  864.                     net_rawout(do_opt, sizeof(do_opt));
  865.                     vtrace_str("SENT %s %s\n", cmd(DO),
  866.                         opt(c));
  867.  
  868.                     /*
  869.                      * For UTS, volunteer to do EOR when
  870.                      * they do.
  871.                      */
  872.                     if (c == TELOPT_EOR && !myopts[c]) {
  873.                         myopts[c] = 1;
  874.                         will_opt[2] = c;
  875.                         net_rawout(will_opt,
  876.                             sizeof(will_opt));
  877.                         vtrace_str("SENT %s %s\n",
  878.                             cmd(WILL), opt(c));
  879.                     }
  880.  
  881.                     check_in3270();
  882.                     check_linemode(False);
  883.                 }
  884.                 break;
  885.             }
  886.             default:
  887.             dont_opt[2] = c;
  888.             net_rawout(dont_opt, sizeof(dont_opt));
  889.             vtrace_str("SENT %s %s\n", cmd(DONT), opt(c));
  890.             break;
  891.         }
  892.         telnet_state = TNS_DATA;
  893.         break;
  894.         case TNS_WONT:    /* telnet WONT DO OPTION command */
  895.         vtrace_str("%s\n", opt(c));
  896.         if (hisopts[c]) {
  897.             hisopts[c] = 0;
  898.             dont_opt[2] = c;
  899.             net_rawout(dont_opt, sizeof(dont_opt));
  900.             vtrace_str("SENT %s %s\n", cmd(DONT), opt(c));
  901.             check_in3270();
  902.             check_linemode(False);
  903.         }
  904.         telnet_state = TNS_DATA;
  905.         break;
  906.         case TNS_DO:    /* telnet PLEASE DO OPTION command */
  907.         vtrace_str("%s\n", opt(c));
  908.         switch (c) {
  909.             case TELOPT_BINARY:
  910.             case TELOPT_EOR:
  911.             case TELOPT_TTYPE:
  912.             case TELOPT_SGA:
  913.             case TELOPT_NAWS:
  914.             case TELOPT_TM:
  915. #if defined(X3270_TN3270E) /*[*/
  916.             case TELOPT_TN3270E:
  917. #endif /*]*/
  918.             if (c != TELOPT_TN3270E || !non_tn3270e_host) {
  919.                 if (!myopts[c]) {
  920.                     if (c != TELOPT_TM)
  921.                         myopts[c] = 1;
  922.                     will_opt[2] = c;
  923.                     net_rawout(will_opt, sizeof(will_opt));
  924.                     vtrace_str("SENT %s %s\n", cmd(WILL),
  925.                         opt(c));
  926.                     check_in3270();
  927.                     check_linemode(False);
  928.                 }
  929.                 if (c == TELOPT_NAWS)
  930.                     send_naws();
  931.                 break;
  932.             }
  933.             default:
  934.             wont_opt[2] = c;
  935.             net_rawout(wont_opt, sizeof(wont_opt));
  936.             vtrace_str("SENT %s %s\n", cmd(WONT), opt(c));
  937.             break;
  938.         }
  939.         telnet_state = TNS_DATA;
  940.         break;
  941.         case TNS_DONT:    /* telnet PLEASE DON'T DO OPTION command */
  942.         vtrace_str("%s\n", opt(c));
  943.         if (myopts[c]) {
  944.             myopts[c] = 0;
  945.             wont_opt[2] = c;
  946.             net_rawout(wont_opt, sizeof(wont_opt));
  947.             vtrace_str("SENT %s %s\n", cmd(WONT), opt(c));
  948.             check_in3270();
  949.             check_linemode(False);
  950.         }
  951.         telnet_state = TNS_DATA;
  952.         break;
  953.         case TNS_SB:    /* telnet sub-option string command */
  954.         if (c == IAC)
  955.             telnet_state = TNS_SB_IAC;
  956.         else
  957.             *sbptr++ = c;
  958.         break;
  959.         case TNS_SB_IAC:    /* telnet sub-option string command */
  960.         *sbptr++ = c;
  961.         if (c == SE) {
  962.             telnet_state = TNS_DATA;
  963.             if (sbbuf[0] == TELOPT_TTYPE &&
  964.                 sbbuf[1] == TELQUAL_SEND) {
  965.                 int tt_len, tb_len;
  966.                 char *tt_out;
  967.  
  968.                 vtrace_str("%s %s\n", opt(sbbuf[0]),
  969.                     telquals[sbbuf[1]]);
  970.                 if (lus != (char **)NULL && try_lu == CN) {
  971.                     /* None of the LUs worked. */
  972.                     popup_an_error("Cannot connect to "
  973.                         "specified LU");
  974.                     return -1;
  975.                 }
  976.  
  977.                 tt_len = strlen(termtype);
  978.                 if (try_lu != CN && *try_lu) {
  979.                     tt_len += strlen(try_lu) + 1;
  980.                     connected_lu = try_lu;
  981.                 } else
  982.                     connected_lu = CN;
  983.  
  984.                 tb_len = 4 + tt_len + 2;
  985.                 tt_out = Malloc(tb_len + 1);
  986.                 (void) sprintf(tt_out, "%c%c%c%c%s%s%s%c%c",
  987.                     IAC, SB, TELOPT_TTYPE, TELQUAL_IS,
  988.                     termtype,
  989.                     (try_lu != CN && *try_lu) ? "@" : "",
  990.                     (try_lu != CN && *try_lu) ? try_lu : "",
  991.                     IAC, SE);
  992.                 net_rawout((unsigned char *)tt_out, tb_len);
  993.  
  994.                 vtrace_str("SENT %s %s %s %.*s %s\n",
  995.                     cmd(SB), opt(TELOPT_TTYPE),
  996.                     telquals[TELQUAL_IS],
  997.                     tt_len, tt_out + 4,
  998.                     cmd(SE));
  999.                 Free(tt_out);
  1000.  
  1001.                 /* Advance to the next LU name. */
  1002.                 next_lu();
  1003.             }
  1004. #if defined(X3270_TN3270E) /*[*/
  1005.             else if (myopts[TELOPT_TN3270E] &&
  1006.                    sbbuf[0] == TELOPT_TN3270E) {
  1007.                 if (tn3270e_negotiate())
  1008.                     return -1;
  1009.             }
  1010. #endif /*]*/
  1011.         } else {
  1012.             telnet_state = TNS_SB;
  1013.         }
  1014.         break;
  1015.     }
  1016.     return 0;
  1017. }
  1018.  
  1019. #if defined(X3270_TN3270E) /*[*/
  1020. /* Send a TN3270E terminal type request. */
  1021. static void
  1022. tn3270e_request(void)
  1023. {
  1024.     int tt_len, tb_len;
  1025.     char *tt_out;
  1026.     char *t;
  1027.  
  1028.     tt_len = strlen(termtype);
  1029.     if (try_lu != CN && *try_lu)
  1030.         tt_len += strlen(try_lu) + 1;
  1031.  
  1032.     tb_len = 5 + tt_len + 2;
  1033.     tt_out = Malloc(tb_len + 1);
  1034.     t = tt_out;
  1035.     t += sprintf(tt_out, "%c%c%c%c%c%s",
  1036.         IAC, SB, TELOPT_TN3270E, TN3270E_OP_DEVICE_TYPE,
  1037.         TN3270E_OP_REQUEST, termtype);
  1038.  
  1039.     /* Convert 3279 to 3278, per the RFC. */
  1040.     if (tt_out[12] == '9')
  1041.         tt_out[12] = '8';
  1042.  
  1043.     if (try_lu != CN && *try_lu)
  1044.         t += sprintf(t, "%c%s", TN3270E_OP_CONNECT, try_lu);
  1045.  
  1046.     (void) sprintf(t, "%c%c", IAC, SE);
  1047.  
  1048.     net_rawout((unsigned char *)tt_out, tb_len);
  1049.  
  1050.     vtrace_str("SENT %s %s DEVICE-TYPE REQUEST %.*s%s%s "
  1051.            "%s\n",
  1052.         cmd(SB), opt(TELOPT_TN3270E), strlen(termtype), tt_out + 5,
  1053.         (try_lu != CN && *try_lu) ? " CONNECT " : "",
  1054.         (try_lu != CN && *try_lu) ? try_lu : "",
  1055.         cmd(SE));
  1056.  
  1057.     Free(tt_out);
  1058. }
  1059.  
  1060. /*
  1061.  * Negotiation of TN3270E options.
  1062.  * Returns 0 if okay, -1 if we have to give up altogether.
  1063.  */
  1064. static int
  1065. tn3270e_negotiate(void)
  1066. {
  1067. #define LU_MAX    32
  1068.     static char reported_lu[LU_MAX+1];
  1069.     static char reported_type[LU_MAX+1];
  1070.     int sblen;
  1071.     unsigned long e_rcvd;
  1072.  
  1073.     /* Find out how long the subnegotiation buffer is. */
  1074.     for (sblen = 0; ; sblen++) {
  1075.         if (sbbuf[sblen] == SE)
  1076.             break;
  1077.     }
  1078.  
  1079.     vtrace_str("TN3270E ");
  1080.  
  1081.     switch (sbbuf[1]) {
  1082.  
  1083.     case TN3270E_OP_SEND:
  1084.  
  1085.         if (sbbuf[2] == TN3270E_OP_DEVICE_TYPE) {
  1086.  
  1087.             /* Host wants us to send our device type. */
  1088.             vtrace_str("SEND DEVICE-TYPE SE\n");
  1089.  
  1090.             tn3270e_request();
  1091.         } else {
  1092.             vtrace_str("SEND ??%u SE\n", sbbuf[2]);
  1093.         }
  1094.         break;
  1095.  
  1096.     case TN3270E_OP_DEVICE_TYPE:
  1097.  
  1098.         /* Device type negotiation. */
  1099.         vtrace_str("DEVICE-TYPE ");
  1100.  
  1101.         switch (sbbuf[2]) {
  1102.         case TN3270E_OP_IS: {
  1103.             int tnlen, snlen;
  1104.  
  1105.             /* Device type success. */
  1106.  
  1107.             /* Isolate the terminal type and session. */
  1108.             tnlen = 0;
  1109.             while (sbbuf[3+tnlen] != SE &&
  1110.                    sbbuf[3+tnlen] != TN3270E_OP_CONNECT)
  1111.                 tnlen++;
  1112.             snlen = 0;
  1113.             if (sbbuf[3+tnlen] == TN3270E_OP_CONNECT) {
  1114.                 while(sbbuf[3+tnlen+1+snlen] != SE)
  1115.                     snlen++;
  1116.             }
  1117.             vtrace_str("IS %.*s CONNECT %.*s SE\n",
  1118.                 tnlen, &sbbuf[3],
  1119.                 snlen, &sbbuf[3+tnlen+1]);
  1120.  
  1121.             /* Remember the LU. */
  1122.             if (tnlen) {
  1123.                 if (tnlen > LU_MAX)
  1124.                     tnlen = LU_MAX;
  1125.                 (void)strncpy(reported_type,
  1126.                     (char *)&sbbuf[3], tnlen);
  1127.                 reported_type[tnlen] = '\0';
  1128.                 connected_type = reported_type;
  1129.             }
  1130.             if (snlen) {
  1131.                 if (snlen > LU_MAX)
  1132.                     snlen = LU_MAX;
  1133.                 (void)strncpy(reported_lu,
  1134.                     (char *)&sbbuf[3+tnlen+1], snlen);
  1135.                 reported_lu[snlen] = '\0';
  1136.                 connected_lu = reported_lu;
  1137.             }
  1138.  
  1139.             /* Tell them what we can do. */
  1140.             tn3270e_subneg_send(TN3270E_OP_REQUEST, e_funcs);
  1141.             break;
  1142.         }
  1143.         case TN3270E_OP_REJECT:
  1144.  
  1145.             /* Device type failure. */
  1146.  
  1147.             vtrace_str("REJECT REASON %s SE\n", rsn(sbbuf[4]));
  1148.  
  1149.             next_lu();
  1150.             if (try_lu != CN) {
  1151.                 /* Try the next LU. */
  1152.                 tn3270e_request();
  1153.             } else if (lus != (char **)NULL) {
  1154.                 /* No more LUs to try.  Give up. */
  1155.                 popup_an_error("Cannot connect to "
  1156.                     "specified LU:\n%s", rsn(sbbuf[4]));
  1157.                 return -1;
  1158.             } else {
  1159.                 popup_an_error("Device type rejected:\n"
  1160.                     "%s", rsn(sbbuf[4]));
  1161.                 return -1;
  1162.             }
  1163.  
  1164.             break;
  1165.         default:
  1166.             vtrace_str("??%u SE\n", sbbuf[2]);
  1167.             break;
  1168.         }
  1169.         break;
  1170.  
  1171.     case TN3270E_OP_FUNCTIONS:
  1172.  
  1173.         /* Functions negotiation. */
  1174.         vtrace_str("FUNCTIONS ");
  1175.  
  1176.         switch (sbbuf[2]) {
  1177.  
  1178.         case TN3270E_OP_REQUEST:
  1179.  
  1180.             /* Host is telling us what functions they want. */
  1181.             vtrace_str("REQUEST %s SE\n",
  1182.                 tn3270e_function_names(sbbuf+3, sblen-3));
  1183.  
  1184.             e_rcvd = tn3270e_fdecode(sbbuf+3, sblen-3);
  1185.             if ((e_rcvd == e_funcs) || (e_funcs & ~e_rcvd)) {
  1186.                 /* They want what we want, or less.  Done. */
  1187.                 e_funcs = e_rcvd;
  1188.                 tn3270e_subneg_send(TN3270E_OP_IS, e_funcs);
  1189.                 tn3270e_negotiated = 1;
  1190.                 vtrace_str("TN3270E option negotiation "
  1191.                     "complete.\n");
  1192.                 check_in3270();
  1193.             } else {
  1194.                 /*
  1195.                  * They want us to do something we can't.
  1196.                  * Request the common subset.
  1197.                  */
  1198.                 e_funcs &= e_rcvd;
  1199.                 tn3270e_subneg_send(TN3270E_OP_REQUEST,
  1200.                     e_funcs);
  1201.             }
  1202.             break;
  1203.  
  1204.         case TN3270E_OP_IS:
  1205.  
  1206.             /* They accept our last request, or a subset thereof. */
  1207.             vtrace_str("IS %s SE\n",
  1208.                 tn3270e_function_names(sbbuf+3, sblen-3));
  1209.             e_rcvd = tn3270e_fdecode(sbbuf+3, sblen-3);
  1210.             if (e_rcvd != e_funcs) {
  1211.                 if (e_funcs & ~e_rcvd) {
  1212.                     /*
  1213.                      * They've removed something.  This is
  1214.                      * technically illegal, but we can
  1215.                      * live with it.
  1216.                      */
  1217.                     e_funcs = e_rcvd;
  1218.                 } else {
  1219.                     /*
  1220.                      * They've added something.  Abandon
  1221.                      * TN3270E, they're brain dead.
  1222.                      */
  1223.                     vtrace_str("Host illegally added "
  1224.                         "function(s), aborting "
  1225.                         "TN3270E\n");
  1226.                     wont_opt[2] = TELOPT_TN3270E;
  1227.                     net_rawout(wont_opt, sizeof(wont_opt));
  1228.                     vtrace_str("SENT %s %s\n", cmd(WONT),
  1229.                         opt(TELOPT_TN3270E));
  1230.                     myopts[TELOPT_TN3270E] = 0;
  1231.                     check_in3270();
  1232.                     break;
  1233.                 }
  1234.             }
  1235.             tn3270e_negotiated = 1;
  1236.             vtrace_str("TN3270E option negotiation complete.\n");
  1237.             check_in3270();
  1238.             break;
  1239.  
  1240.         default:
  1241.             vtrace_str("??%u SE\n", sbbuf[2]);
  1242.             break;
  1243.         }
  1244.         break;
  1245.  
  1246.     default:
  1247.         vtrace_str("??%u SE\n", sbbuf[1]);
  1248.     }
  1249.  
  1250.     /* Good enough for now. */
  1251.     return 0;
  1252. }
  1253.  
  1254. /* Expand a string of TN3270E function codes into text. */
  1255. static const char *
  1256. tn3270e_function_names(const unsigned char *buf, int len)
  1257. {
  1258.     int i;
  1259.     static char text_buf[1024];
  1260.     char *s = text_buf;
  1261.  
  1262.     if (!len)
  1263.         return("(null)");
  1264.     for (i = 0; i < len; i++) {
  1265.         s += sprintf(s, "%s%s", (s == text_buf) ? "" : " ",
  1266.             fnn(buf[i]));
  1267.     }
  1268.     return text_buf;
  1269. }
  1270.  
  1271. /* Expand the current TN3270E function codes into text. */
  1272. const char *
  1273. tn3270e_current_opts(void)
  1274. {
  1275.     int i;
  1276.     static char text_buf[1024];
  1277.     char *s = text_buf;
  1278.  
  1279.     if (!e_funcs || !IN_E)
  1280.         return CN;
  1281.     for (i = 0; i < 32; i++) {
  1282.         if (e_funcs & E_OPT(i))
  1283.         s += sprintf(s, "%s%s", (s == text_buf) ? "" : " ",
  1284.             fnn(i));
  1285.     }
  1286.     return text_buf;
  1287. }
  1288.  
  1289. /* Transmit a TN3270E FUNCTIONS REQUEST or FUNCTIONS IS message. */
  1290. static void
  1291. tn3270e_subneg_send(unsigned char op, unsigned long funcs)
  1292. {
  1293.     unsigned char proto_buf[7 + 32];
  1294.     int proto_len;
  1295.     int i;
  1296.  
  1297.     /* Construct the buffers. */
  1298.     (void) memcpy(proto_buf, functions_req, 4);
  1299.     proto_buf[4] = op;
  1300.     proto_len = 5;
  1301.     for (i = 0; i < 32; i++) {
  1302.         if (funcs & E_OPT(i))
  1303.             proto_buf[proto_len++] = i;
  1304.     }
  1305.  
  1306.     /* Complete and send out the protocol message. */
  1307.     proto_buf[proto_len++] = IAC;
  1308.     proto_buf[proto_len++] = SE;
  1309.     net_rawout(proto_buf, proto_len);
  1310.  
  1311.     /* Complete and send out the trace text. */
  1312.     vtrace_str("SENT %s %s FUNCTIONS %s %s %s\n",
  1313.         cmd(SB), opt(TELOPT_TN3270E),
  1314.         (op == TN3270E_OP_REQUEST)? "REQUEST": "IS",
  1315.         tn3270e_function_names(proto_buf + 5, proto_len - 7),
  1316.         cmd(SE));
  1317. }
  1318.  
  1319. /* Translate a string of TN3270E functions into a bit-map. */
  1320. static unsigned long
  1321. tn3270e_fdecode(const unsigned char *buf, int len)
  1322. {
  1323.     unsigned long r = 0L;
  1324.     int i;
  1325.  
  1326.     /* Note that this code silently ignores options >= 32. */
  1327.     for (i = 0; i < len; i++) {
  1328.         if (buf[i] < 32)
  1329.             r |= E_OPT(buf[i]);
  1330.     }
  1331.     return r;
  1332. }
  1333. #endif /*]*/
  1334.  
  1335. static int
  1336. process_eor(void)
  1337. {
  1338.     if (syncing || !(ibptr - ibuf))
  1339.         return(0);
  1340.  
  1341. #if defined(X3270_TN3270E) /*[*/
  1342.     if (IN_E) {
  1343.         tn3270e_header *h = (tn3270e_header *)ibuf;
  1344.         unsigned char *s;
  1345.         enum pds rv;
  1346.  
  1347.         vtrace_str("RCVD TN3270E(%s%s %s %u)\n",
  1348.             e_dt(h->data_type),
  1349.             e_rq(h->data_type, h->request_flag),
  1350.             e_rsp(h->data_type, h->response_flag),
  1351.             h->seq_number[0] << 8 | h->seq_number[1]);
  1352.  
  1353.         switch (h->data_type) {
  1354.         case TN3270E_DT_3270_DATA:
  1355.             if ((e_funcs & E_OPT(TN3270E_FUNC_BIND_IMAGE)) &&
  1356.                 !tn3270e_bound)
  1357.                 return 0;
  1358.             tn3270e_submode = E_3270;
  1359.             check_in3270();
  1360.             response_required = h->response_flag;
  1361.             rv = process_ds(ibuf + EH_SIZE,
  1362.                 (ibptr - ibuf) - EH_SIZE);
  1363.             if (rv < 0 &&
  1364.                 response_required != TN3270E_RSF_NO_RESPONSE)
  1365.                 tn3270e_nak(rv);
  1366.             else if (rv == PDS_OKAY_NO_OUTPUT &&
  1367.                 response_required == TN3270E_RSF_ALWAYS_RESPONSE)
  1368.                 tn3270e_ack();
  1369.             response_required = TN3270E_RSF_NO_RESPONSE;
  1370.             return 0;
  1371.         case TN3270E_DT_BIND_IMAGE:
  1372.             if (!(e_funcs & E_OPT(TN3270E_FUNC_BIND_IMAGE)))
  1373.                 return 0;
  1374.             tn3270e_bound = 1;
  1375.             check_in3270();
  1376.             return 0;
  1377.         case TN3270E_DT_UNBIND:
  1378.             if (!(e_funcs & E_OPT(TN3270E_FUNC_BIND_IMAGE)))
  1379.                 return 0;
  1380.             tn3270e_bound = 0;
  1381.             if (tn3270e_submode == E_3270)
  1382.                 tn3270e_submode = E_NONE;
  1383.             check_in3270();
  1384.             return 0;
  1385.         case TN3270E_DT_NVT_DATA:
  1386.             /* In tn3270e NVT mode */
  1387.             tn3270e_submode = E_NVT;
  1388.             check_in3270();
  1389.             for (s = ibuf; s < ibptr; s++) {
  1390.                 ansi_process(*s++);
  1391.             }
  1392.             return 0;
  1393.         case TN3270E_DT_SSCP_LU_DATA:
  1394.             if (!(e_funcs & E_OPT(TN3270E_FUNC_BIND_IMAGE)))
  1395.                 return 0;
  1396.             tn3270e_submode = E_SSCP;
  1397.             check_in3270();
  1398.             ctlr_write_sscp_lu(ibuf + EH_SIZE,
  1399.                                (ibptr - ibuf) - EH_SIZE);
  1400.             return 0;
  1401.         default:
  1402.             /* Should do something more extraordinary here. */
  1403.             return 0;
  1404.         }
  1405.     } else
  1406. #endif /*]*/
  1407.     {
  1408.         (void) process_ds(ibuf, ibptr - ibuf);
  1409.     }
  1410.     return 0;
  1411. }
  1412.  
  1413.  
  1414. /*
  1415.  * net_exception
  1416.  *    Called when there is an exceptional condition on the socket.
  1417.  */
  1418. void
  1419. net_exception(void)
  1420. {
  1421.     trace_str("RCVD urgent data indication\n");
  1422.     if (!syncing) {
  1423.         syncing = 1;
  1424.         x_except_off();
  1425.     }
  1426. }
  1427.  
  1428. /*
  1429.  * Flavors of Network Output:
  1430.  *
  1431.  *   3270 mode
  1432.  *    net_output    send a 3270 record
  1433.  *
  1434.  *   ANSI mode; call each other in turn
  1435.  *    net_sendc    net_cookout for 1 byte
  1436.  *    net_sends    net_cookout for a null-terminated string
  1437.  *    net_cookout    send user data with cooked-mode processing, ANSI mode
  1438.  *    net_cookedout    send user data, ANSI mode, already cooked
  1439.  *    net_rawout    send telnet protocol data, ANSI mode
  1440.  *
  1441.  */
  1442.  
  1443.  
  1444. /*
  1445.  * net_rawout
  1446.  *    Send out raw telnet data.  We assume that there will always be enough
  1447.  *    space to buffer what we want to transmit, so we don't handle EAGAIN or
  1448.  *    EWOULDBLOCK.
  1449.  */
  1450. static void
  1451. net_rawout(unsigned const char *buf, int len)
  1452. {
  1453.     int    nw;
  1454.  
  1455. #if defined(X3270_TRACE) /*[*/
  1456.     trace_netdata('>', buf, len);
  1457. #endif /*]*/
  1458.  
  1459.     while (len) {
  1460. #if defined(OMTU) /*[*/
  1461.         int n2w = len;
  1462.         int pause = 0;
  1463.  
  1464.         if (n2w > OMTU) {
  1465.             n2w = OMTU;
  1466.             pause = 1;
  1467.         }
  1468. #else
  1469. #        define n2w len
  1470. #endif
  1471.         nw = write(sock, (const char *) buf, n2w);
  1472.         if (nw < 0) {
  1473.             vtrace_str("RCVD socket error %d\n", errno);
  1474.             if (errno == EPIPE || errno == ECONNRESET) {
  1475.                 host_disconnect(False);
  1476.                 return;
  1477.             } else if (errno == EINTR) {
  1478.                 goto bot;
  1479.             } else {
  1480.                 popup_an_errno(errno, "Socket write");
  1481.                 host_disconnect(True);
  1482.                 return;
  1483.             }
  1484.         }
  1485.         ns_bsent += nw;
  1486.         len -= nw;
  1487.         buf += nw;
  1488.         bot:
  1489. #if defined(OMTU) /*[*/
  1490.         if (pause)
  1491.             sleep(1);
  1492. #endif /*]*/
  1493.         ;
  1494.     }
  1495. }
  1496.  
  1497.  
  1498. #if defined(X3270_ANSI) /*[*/
  1499. /*
  1500.  * net_hexansi_out
  1501.  *    Send uncontrolled user data to the host in ANSI mode, performing IAC
  1502.  *    and CR quoting as necessary.
  1503.  */
  1504. void
  1505. net_hexansi_out(unsigned char *buf, int len)
  1506. {
  1507.     unsigned char *tbuf;
  1508.     unsigned char *xbuf;
  1509.  
  1510.     if (!len)
  1511.         return;
  1512.  
  1513. #if defined(X3270_TRACE) /*[*/
  1514.     /* Trace the data. */
  1515.     if (toggled(DS_TRACE)) {
  1516.         int i;
  1517.  
  1518.         (void) fprintf(tracef, ">");
  1519.         for (i = 0; i < len; i++)
  1520.             (void) fprintf(tracef, " %s", ctl_see((int) *(buf+i)));
  1521.         (void) fprintf(tracef, "\n");
  1522.     }
  1523. #endif /*]*/
  1524.  
  1525.     /* Expand it. */
  1526.     tbuf = xbuf = (unsigned char *)Malloc(2*len);
  1527.     while (len) {
  1528.         unsigned char c = *buf++;
  1529.  
  1530.         *tbuf++ = c;
  1531.         len--;
  1532.         if (c == IAC)
  1533.             *tbuf++ = IAC;
  1534.         else if (c == '\r' && (!len || *buf != '\n'))
  1535.             *tbuf++ = '\0';
  1536.     }
  1537.  
  1538.     /* Send it to the host. */
  1539.     net_rawout(xbuf, tbuf - xbuf);
  1540.     Free((XtPointer)xbuf);
  1541. }
  1542.  
  1543. /*
  1544.  * net_cookedout
  1545.  *    Send user data out in ANSI mode, without cooked-mode processing.
  1546.  */
  1547. static void
  1548. net_cookedout(const char *buf, int len)
  1549. {
  1550. #if defined(X3270_TRACE) /*[*/
  1551.     if (toggled(DS_TRACE)) {
  1552.         int i;
  1553.  
  1554.         (void) fprintf(tracef, ">");
  1555.         for (i = 0; i < len; i++)
  1556.             (void) fprintf(tracef, " %s", ctl_see((int) *(buf+i)));
  1557.         (void) fprintf(tracef, "\n");
  1558.     }
  1559. #endif /*]*/
  1560.     net_rawout((unsigned const char *) buf, len);
  1561. }
  1562.  
  1563.  
  1564. /*
  1565.  * net_cookout
  1566.  *    Send output in ANSI mode, including cooked-mode processing if
  1567.  *    appropriate.
  1568.  */
  1569. static void
  1570. net_cookout(const char *buf, int len)
  1571. {
  1572.  
  1573.     if (!IN_ANSI || (kybdlock & KL_AWAITING_FIRST))
  1574.         return;
  1575.  
  1576.     if (linemode) {
  1577.         register int    i;
  1578.         char    c;
  1579.  
  1580.         for (i = 0; i < len; i++) {
  1581.             c = buf[i];
  1582.  
  1583.             /* Input conversions. */
  1584.             if (!lnext && c == '\r' && appres.icrnl)
  1585.                 c = '\n';
  1586.             else if (!lnext && c == '\n' && appres.inlcr)
  1587.                 c = '\r';
  1588.  
  1589.             /* Backslashes. */
  1590.             if (c == '\\' && !backslashed)
  1591.                 backslashed = 1;
  1592.             else
  1593.                 backslashed = 0;
  1594.  
  1595.             /* Control chars. */
  1596.             if (c == '\n')
  1597.                 do_eol(c);
  1598.             else if (c == vintr)
  1599.                 do_intr(c);
  1600.             else if (c == vquit)
  1601.                 do_quit(c);
  1602.             else if (c == verase)
  1603.                 do_cerase(c);
  1604.             else if (c == vkill)
  1605.                 do_kill(c);
  1606.             else if (c == vwerase)
  1607.                 do_werase(c);
  1608.             else if (c == vrprnt)
  1609.                 do_rprnt(c);
  1610.             else if (c == veof)
  1611.                 do_eof(c);
  1612.             else if (c == vlnext)
  1613.                 do_lnext(c);
  1614.             else
  1615.                 do_data(c);
  1616.         }
  1617.         return;
  1618.     } else
  1619.         net_cookedout(buf, len);
  1620. }
  1621.  
  1622.  
  1623. /*
  1624.  * Cooked mode input processing.
  1625.  */
  1626.  
  1627. static void
  1628. cooked_init(void)
  1629. {
  1630.     if (lbuf == (unsigned char *)NULL)
  1631.         lbuf = (unsigned char *)Malloc(BUFSZ);
  1632.     lbptr = lbuf;
  1633.     lnext = 0;
  1634.     backslashed = 0;
  1635. }
  1636.  
  1637. static void
  1638. ansi_process_s(const char *data)
  1639. {
  1640.     while (*data)
  1641.         ansi_process((unsigned int) *data++);
  1642. }
  1643.  
  1644. static void
  1645. forward_data(void)
  1646. {
  1647.     net_cookedout((char *) lbuf, lbptr - lbuf);
  1648.     cooked_init();
  1649. }
  1650.  
  1651. static void
  1652. do_data(char c)
  1653. {
  1654.     if (lbptr+1 < lbuf + BUFSZ) {
  1655.         *lbptr++ = c;
  1656.         if (c == '\r')
  1657.             *lbptr++ = '\0';
  1658.         if (c == '\t')
  1659.             ansi_process((unsigned int) c);
  1660.         else
  1661.             ansi_process_s(ctl_see((int) c));
  1662.     } else
  1663.         ansi_process_s("\007");
  1664.     lnext = 0;
  1665.     backslashed = 0;
  1666. }
  1667.  
  1668. static void
  1669. do_intr(char c)
  1670. {
  1671.     if (lnext) {
  1672.         do_data(c);
  1673.         return;
  1674.     }
  1675.     ansi_process_s(ctl_see((int) c));
  1676.     cooked_init();
  1677.     net_interrupt();
  1678. }
  1679.  
  1680. static void
  1681. do_quit(char c)
  1682. {
  1683.     if (lnext) {
  1684.         do_data(c);
  1685.         return;
  1686.     }
  1687.     ansi_process_s(ctl_see((int) c));
  1688.     cooked_init();
  1689.     net_break();
  1690. }
  1691.  
  1692. static void
  1693. do_cerase(char c)
  1694. {
  1695.     int len;
  1696.  
  1697.     if (backslashed) {
  1698.         lbptr--;
  1699.         ansi_process_s("\b");
  1700.         do_data(c);
  1701.         return;
  1702.     }
  1703.     if (lnext) {
  1704.         do_data(c);
  1705.         return;
  1706.     }
  1707.     if (lbptr > lbuf) {
  1708.         len = strlen(ctl_see((int) *--lbptr));
  1709.  
  1710.         while (len--)
  1711.             ansi_process_s("\b \b");
  1712.     }
  1713. }
  1714.  
  1715. static void
  1716. do_werase(char c)
  1717. {
  1718.     int any = 0;
  1719.     int len;
  1720.  
  1721.     if (lnext) {
  1722.         do_data(c);
  1723.         return;
  1724.     }
  1725.     while (lbptr > lbuf) {
  1726.         char ch = *--lbptr;
  1727.  
  1728.         if (ch == ' ' || ch == '\t') {
  1729.             if (any) {
  1730.                 ++lbptr;
  1731.                 break;
  1732.             }
  1733.         } else
  1734.             any = 1;
  1735.         len = strlen(ctl_see((int) ch));
  1736.  
  1737.         while (len--)
  1738.             ansi_process_s("\b \b");
  1739.     }
  1740. }
  1741.  
  1742. static void
  1743. do_kill(char c)
  1744. {
  1745.     int i, len;
  1746.  
  1747.     if (backslashed) {
  1748.         lbptr--;
  1749.         ansi_process_s("\b");
  1750.         do_data(c);
  1751.         return;
  1752.     }
  1753.     if (lnext) {
  1754.         do_data(c);
  1755.         return;
  1756.     }
  1757.     while (lbptr > lbuf) {
  1758.         len = strlen(ctl_see((int) *--lbptr));
  1759.  
  1760.         for (i = 0; i < len; i++)
  1761.             ansi_process_s("\b \b");
  1762.     }
  1763. }
  1764.  
  1765. static void
  1766. do_rprnt(char c)
  1767. {
  1768.     unsigned char *p;
  1769.  
  1770.     if (lnext) {
  1771.         do_data(c);
  1772.         return;
  1773.     }
  1774.     ansi_process_s(ctl_see((int) c));
  1775.     ansi_process_s("\r\n");
  1776.     for (p = lbuf; p < lbptr; p++)
  1777.         ansi_process_s(ctl_see((int) *p));
  1778. }
  1779.  
  1780. static void
  1781. do_eof(char c)
  1782. {
  1783.     if (backslashed) {
  1784.         lbptr--;
  1785.         ansi_process_s("\b");
  1786.         do_data(c);
  1787.         return;
  1788.     }
  1789.     if (lnext) {
  1790.         do_data(c);
  1791.         return;
  1792.     }
  1793.     do_data(c);
  1794.     forward_data();
  1795. }
  1796.  
  1797. static void
  1798. do_eol(char c)
  1799. {
  1800.     if (lnext) {
  1801.         do_data(c);
  1802.         return;
  1803.     }
  1804.     if (lbptr+2 >= lbuf + BUFSZ) {
  1805.         ansi_process_s("\007");
  1806.         return;
  1807.     }
  1808.     *lbptr++ = '\r';
  1809.     *lbptr++ = '\n';
  1810.     ansi_process_s("\r\n");
  1811.     forward_data();
  1812. }
  1813.  
  1814. static void
  1815. do_lnext(char c)
  1816. {
  1817.     if (lnext) {
  1818.         do_data(c);
  1819.         return;
  1820.     }
  1821.     lnext = 1;
  1822.     ansi_process_s("^\b");
  1823. }
  1824. #endif /*]*/
  1825.  
  1826.  
  1827.  
  1828. /*
  1829.  * check_in3270
  1830.  *    Check for switches between NVT, SSCP-LU and 3270 modes.
  1831.  */
  1832. static void
  1833. check_in3270(void)
  1834. {
  1835.     enum cstate new_cstate = NOT_CONNECTED;
  1836.     static const char *state_name[] = {
  1837.         "unconnected",
  1838.         "pending",
  1839.         "connected initial",
  1840.         "TN3270 NVT",
  1841.         "TN3270 3270",
  1842.         "TN3270E",
  1843.         "TN3270E NVT",
  1844.         "TN3270E SSCP-LU",
  1845.         "TN3270E 3270"
  1846.     };
  1847.  
  1848. #if defined(X3270_TN3270E) /*[*/
  1849.     if (myopts[TELOPT_TN3270E]) {
  1850.         if (!tn3270e_negotiated)
  1851.             new_cstate = CONNECTED_INITIAL_E;
  1852.         else switch (tn3270e_submode) {
  1853.         case E_NONE:
  1854.             new_cstate = CONNECTED_INITIAL_E;
  1855.             break;
  1856.         case E_NVT:
  1857.             new_cstate = CONNECTED_NVT;
  1858.             break;
  1859.         case E_3270:
  1860.             new_cstate = CONNECTED_TN3270E;
  1861.             break;
  1862.         case E_SSCP:
  1863.             new_cstate = CONNECTED_SSCP;
  1864.             break;
  1865.         }
  1866.     } else
  1867. #endif /*]*/
  1868.     if (myopts[TELOPT_BINARY] &&
  1869.                myopts[TELOPT_EOR] &&
  1870.                myopts[TELOPT_TTYPE] &&
  1871.                hisopts[TELOPT_BINARY] &&
  1872.                hisopts[TELOPT_EOR]) {
  1873.         new_cstate = CONNECTED_3270;
  1874.     } else if (cstate == CONNECTED_INITIAL) {
  1875.         /* Nothing has happened, yet. */
  1876.         return;
  1877.     } else {
  1878.         new_cstate = CONNECTED_ANSI;
  1879.     }
  1880.  
  1881.     if (new_cstate != cstate) {
  1882. #if defined(X3270_TN3270E) /*[*/
  1883.         int was_in_e = IN_E;
  1884. #endif /*]*/
  1885.  
  1886.         vtrace_str("Now operating in %s mode.\n",
  1887.             state_name[new_cstate]);
  1888.         host_in3270(new_cstate);
  1889.  
  1890. #if defined(X3270_TN3270E) /*[*/
  1891.         /*
  1892.          * If we've now switched between non-TN3270E mode and
  1893.          * TN3270E mode, reset the LU list so we can try again
  1894.          * in the new mode.
  1895.          */
  1896.         if (lus != (char **)NULL && was_in_e != IN_E) {
  1897.             curr_lu = lus;
  1898.             try_lu = *curr_lu;
  1899.         }
  1900. #endif /*]*/
  1901.  
  1902.         /* Allocate the initial 3270 input buffer. */
  1903.         if (new_cstate >= CONNECTED_INITIAL && !ibuf_size) {
  1904.             ibuf = (unsigned char *)Malloc(BUFSIZ);
  1905.             ibuf_size = BUFSIZ;
  1906.             ibptr = ibuf;
  1907.         }
  1908.  
  1909. #if defined(X3270_ANSI) /*[*/
  1910.         /* Reinitialize line mode. */
  1911.         if ((new_cstate == CONNECTED_ANSI && linemode) ||
  1912.             new_cstate == CONNECTED_NVT)
  1913.             cooked_init();
  1914. #endif /*]*/
  1915.  
  1916. #if defined(X3270_TN3270E) /*[*/
  1917.         /* If we fell out of TN3270E, remove the state. */
  1918.         if (!myopts[TELOPT_TN3270E]) {
  1919.             tn3270e_negotiated = 0;
  1920.             tn3270e_submode = E_NONE;
  1921.             tn3270e_bound = 0;
  1922.         }
  1923. #endif /*]*/
  1924.     }
  1925. }
  1926.  
  1927. /*
  1928.  * store3270in
  1929.  *    Store a character in the 3270 input buffer, checking for buffer
  1930.  *    overflow and reallocating ibuf if necessary.
  1931.  */
  1932. static void
  1933. store3270in(unsigned char c)
  1934. {
  1935.     if (ibptr - ibuf >= ibuf_size) {
  1936.         ibuf_size += BUFSIZ;
  1937.         ibuf = (unsigned char *)Realloc((char *)ibuf, ibuf_size);
  1938.         ibptr = ibuf + ibuf_size - BUFSIZ;
  1939.     }
  1940.     *ibptr++ = c;
  1941. }
  1942.  
  1943. /*
  1944.  * space3270out
  1945.  *    Ensure that <n> more characters will fit in the 3270 output buffer.
  1946.  *    Allocates the buffer in BUFSIZ chunks.
  1947.  *    Allocates hidden space at the front of the buffer for TN3270E.
  1948.  */
  1949. void
  1950. space3270out(int n)
  1951. {
  1952.     unsigned nc = 0;    /* amount of data currently in obuf */
  1953.     unsigned more = 0;
  1954.  
  1955.     if (obuf_size)
  1956.         nc = obptr - obuf;
  1957.  
  1958.     while ((nc + n + EH_SIZE) > (obuf_size + more)) {
  1959.         more += BUFSIZ;
  1960.     }
  1961.  
  1962.     if (more) {
  1963.         obuf_size += more;
  1964.         obuf_base = (unsigned char *)Realloc((char *)obuf_base,
  1965.             obuf_size);
  1966.         obuf = obuf_base + EH_SIZE;
  1967.         obptr = obuf + nc;
  1968.     }
  1969. }
  1970.  
  1971.  
  1972. /*
  1973.  * check_linemode
  1974.  *    Set the global variable 'linemode', which says whether we are in
  1975.  *    character-by-character mode or line mode.
  1976.  */
  1977. static void
  1978. check_linemode(Boolean init)
  1979. {
  1980.     int wasline = linemode;
  1981.  
  1982.     /*
  1983.      * The next line is a deliberate kluge to effectively ignore the SGA
  1984.      * option.  If the host will echo for us, we assume
  1985.      * character-at-a-time; otherwise we assume fully cooked by us.
  1986.      *
  1987.      * This allows certain IBM hosts which volunteer SGA but refuse
  1988.      * ECHO to operate more-or-less normally, at the expense of
  1989.      * implementing the (hopefully useless) "character-at-a-time, local
  1990.      * echo" mode.
  1991.      *
  1992.      * We still implement "switch to line mode" and "switch to character
  1993.      * mode" properly by asking for both SGA and ECHO to be off or on, but
  1994.      * we basically ignore the reply for SGA.
  1995.      */
  1996.     linemode = !hisopts[TELOPT_ECHO] /* && !hisopts[TELOPT_SGA] */;
  1997.  
  1998.     if (init || linemode != wasline) {
  1999.         st_changed(ST_LINE_MODE, linemode);
  2000.         if (!init) {
  2001.             vtrace_str("Operating in %s mode.\n",
  2002.                 linemode ? "line" : "character-at-a-time");
  2003.         }
  2004. #if defined(X3270_ANSI) /*[*/
  2005.         if (IN_ANSI && linemode)
  2006.             cooked_init();
  2007. #endif /*]*/
  2008.     }
  2009. }
  2010.  
  2011.  
  2012. #if defined(X3270_TRACE) /*[*/
  2013.  
  2014. /*
  2015.  * nnn
  2016.  *    Expands a number to a character string, for displaying unknown telnet
  2017.  *    commands and options.
  2018.  */
  2019. static const char *
  2020. nnn(int c)
  2021. {
  2022.     static char    buf[64];
  2023.  
  2024.     (void) sprintf(buf, "%d", c);
  2025.     return buf;
  2026. }
  2027.  
  2028. /*
  2029.  * cmd
  2030.  *    Expands a TELNET command into a character string.
  2031.  */
  2032. static const char *
  2033. cmd(unsigned char c)
  2034. {
  2035.     if (TELCMD_OK(c))
  2036.         return TELCMD(c);
  2037.     else
  2038.         return nnn((int)c);
  2039. }
  2040.  
  2041. /*
  2042.  * opt
  2043.  *    Expands a TELNET option into a character string.
  2044.  */
  2045. static const char *
  2046. opt(unsigned char c)
  2047. {
  2048.     if (TELOPT_OK(c))
  2049.         return TELOPT(c);
  2050.     else if (c == TELOPT_TN3270E)
  2051.         return "TN3270E";
  2052.     else
  2053.         return nnn((int)c);
  2054. }
  2055.  
  2056.  
  2057. #define LINEDUMP_MAX    32
  2058.  
  2059. void
  2060. trace_netdata(char direction, unsigned const char *buf, int len)
  2061. {
  2062.     int offset;
  2063.     struct timeval ts;
  2064.     double tdiff;
  2065.  
  2066.     if (!toggled(DS_TRACE))
  2067.         return;
  2068.     (void) gettimeofday(&ts, (struct timezone *)NULL);
  2069.     if (IN_3270) {
  2070.         tdiff = ((1.0e6 * (double)(ts.tv_sec - ds_ts.tv_sec)) +
  2071.             (double)(ts.tv_usec - ds_ts.tv_usec)) / 1.0e6;
  2072.         (void) fprintf(tracef, "%c +%gs\n", direction, tdiff);
  2073.     }
  2074.     ds_ts = ts;
  2075.     for (offset = 0; offset < len; offset++) {
  2076.         if (!(offset % LINEDUMP_MAX))
  2077.             (void) fprintf(tracef, "%s%c 0x%-3x ",
  2078.                 (offset ? "\n" : ""), direction, offset);
  2079.         (void) fprintf(tracef, "%02x", buf[offset]);
  2080.     }
  2081.     (void) fprintf(tracef, "\n");
  2082. }
  2083. #endif /*]*/
  2084.  
  2085.  
  2086. /*
  2087.  * net_output
  2088.  *    Send 3270 output over the network, prepending TN3270E headers and
  2089.  *    tacking on the necessary telnet end-of-record command.
  2090.  */
  2091. void
  2092. net_output(void)
  2093. {
  2094. #if defined(X3270_TN3270E) /*[*/
  2095. #define BSTART    ((IN_TN3270E || IN_SSCP) ? obuf_base : obuf)
  2096. #else /*][*/
  2097. #define BSTART    obuf
  2098. #endif /*]*/
  2099.  
  2100. #if defined(X3270_TN3270E) /*[*/
  2101.     /* Set the TN3720E header. */
  2102.     if (IN_TN3270E || IN_SSCP) {
  2103.         tn3270e_header *h = (tn3270e_header *)obuf_base;
  2104.  
  2105.         /* Check for sending a TN3270E response. */
  2106.         if (response_required == TN3270E_RSF_ALWAYS_RESPONSE) {
  2107.             tn3270e_ack();
  2108.             response_required = TN3270E_RSF_NO_RESPONSE;
  2109.         }
  2110.  
  2111.         /* Set the outbound TN3270E header. */
  2112.         h->data_type = IN_TN3270E ?
  2113.             TN3270E_DT_3270_DATA : TN3270E_DT_SSCP_LU_DATA;
  2114.         h->request_flag = 0;
  2115.         h->response_flag = 0;
  2116.         h->seq_number[0] = (e_xmit_seq >> 8) & 0xff;
  2117.         h->seq_number[1] = e_xmit_seq & 0xff;
  2118.     }
  2119. #endif /*]*/
  2120.  
  2121.     /* Count the number of IACs in the message. */
  2122.     {
  2123.         char *buf = (char *)BSTART;
  2124.         int len = obptr - BSTART;
  2125.         char *iac;
  2126.         int cnt = 0;
  2127.  
  2128.         while (len && (iac = memchr(buf, IAC, len)) != CN) {
  2129.             cnt++;
  2130.             len -= iac - buf + 1;
  2131.             buf = iac + 1;
  2132.         }
  2133.         if (cnt) {
  2134.             space3270out(cnt);
  2135.             len = obptr - BSTART;
  2136.             buf = (char *)BSTART;
  2137.  
  2138.             /* Now quote them. */
  2139.             while (len && (iac = memchr(buf, IAC, len)) != CN) {
  2140.                 int ml = len - (iac - buf);
  2141.  
  2142.                 (void) memmove(iac + 1, iac, ml);
  2143.                 len -= iac - buf + 1;
  2144.                 buf = iac + 2;
  2145.                 obptr++;
  2146.             }
  2147.         }
  2148.     }
  2149.  
  2150.     /* Add IAC EOR to the end and send it. */
  2151.     space3270out(2);
  2152.     *obptr++ = IAC;
  2153.     *obptr++ = EOR;
  2154. #if defined(X3270_TN3270E) /*[*/
  2155.     if (IN_TN3270E || IN_SSCP) {
  2156.         vtrace_str("SENT TN3270E(%s NO-RESPONSE %u)\n",
  2157.             IN_TN3270E ? "3270-DATA" : "SSCP-LU-DATA", e_xmit_seq);
  2158.         if (e_funcs & E_OPT(TN3270E_FUNC_RESPONSES))
  2159.             e_xmit_seq = (e_xmit_seq + 1) & 0x7fff;
  2160.     }
  2161. #endif /*]*/
  2162.     net_rawout(BSTART, obptr - BSTART);
  2163.  
  2164.     trace_str("SENT EOR\n");
  2165.     ns_rsent++;
  2166. #undef BSTART
  2167. }
  2168.  
  2169. #if defined(X3270_TN3270E) /*[*/
  2170. /* Send a TN3270E positive response to the server. */
  2171. static void
  2172. tn3270e_ack(void)
  2173. {
  2174.     unsigned char rsp_buf[9];
  2175.     tn3270e_header *h, *h_in;
  2176.     int rsp_len = EH_SIZE;
  2177.  
  2178.     h = (tn3270e_header *)rsp_buf;
  2179.     h_in = (tn3270e_header *)ibuf;
  2180.  
  2181.     h->data_type = TN3270E_DT_RESPONSE;
  2182.     h->request_flag = 0;
  2183.     h->response_flag = TN3270E_RSF_POSITIVE_RESPONSE;
  2184.     h->seq_number[0] = h_in->seq_number[0];
  2185.     h->seq_number[1] = h_in->seq_number[1];
  2186.     if (h->seq_number[1] == IAC)
  2187.         rsp_buf[rsp_len++] = IAC;
  2188.     rsp_buf[rsp_len++] = TN3270E_POS_DEVICE_END;
  2189.     rsp_buf[rsp_len++] = IAC;
  2190.     rsp_buf[rsp_len++] = EOR;
  2191.     vtrace_str("SENT TN3270E(RESPONSE POSITIVE-RESPONSE "
  2192.         "%u) DEVICE-END\n",
  2193.         h_in->seq_number[0] << 8 | h_in->seq_number[1]);
  2194.     net_rawout(rsp_buf, rsp_len);
  2195. }
  2196.  
  2197. /* Send a TN3270E negative response to the server. */
  2198. static void
  2199. tn3270e_nak(enum pds rv unused)
  2200. {
  2201.     unsigned char rsp_buf[9];
  2202.     tn3270e_header *h, *h_in;
  2203.     int rsp_len = EH_SIZE;
  2204.  
  2205.     h = (tn3270e_header *)rsp_buf;
  2206.     h_in = (tn3270e_header *)ibuf;
  2207.  
  2208.     h->data_type = TN3270E_DT_RESPONSE;
  2209.     h->request_flag = 0;
  2210.     h->response_flag = TN3270E_RSF_NEGATIVE_RESPONSE;
  2211.     h->seq_number[0] = h_in->seq_number[0];
  2212.     h->seq_number[1] = h_in->seq_number[1];
  2213.     if (h->seq_number[1] == IAC)
  2214.         rsp_buf[rsp_len++] = IAC;
  2215.     rsp_buf[rsp_len++] = TN3270E_NEG_COMMAND_REJECT;
  2216.     rsp_buf[rsp_len++] = IAC;
  2217.     rsp_buf[rsp_len++] = EOR;
  2218.     vtrace_str("SENT TN3270E(RESPONSE NEGATIVE-RESPONSE %u) "
  2219.         "COMMAND-REJECT\n",
  2220.         h_in->seq_number[0] << 8 | h_in->seq_number[1]);
  2221.     net_rawout(rsp_buf, rsp_len);
  2222. }
  2223.  
  2224. #if defined(X3270_TRACE) /*[*/
  2225. /* Add a dummy TN3270E header to the output buffer. */
  2226. Boolean
  2227. net_add_dummy_tn3270e(void)
  2228. {
  2229.     tn3270e_header *h;
  2230.  
  2231.     if (!IN_E || tn3270e_submode == E_NONE)
  2232.         return False;
  2233.  
  2234.     space3270out(EH_SIZE);
  2235.     h = (tn3270e_header *)obptr;
  2236.  
  2237.     switch (tn3270e_submode) {
  2238.     case E_NONE:
  2239.         break;
  2240.     case E_NVT:
  2241.         h->data_type = TN3270E_DT_NVT_DATA;
  2242.         break;
  2243.     case E_SSCP:
  2244.         h->data_type = TN3270E_DT_SSCP_LU_DATA;
  2245.         break;
  2246.     case E_3270:
  2247.         h->data_type = TN3270E_DT_3270_DATA;
  2248.         break;
  2249.     }
  2250.     h->request_flag = 0;
  2251.     h->response_flag = TN3270E_RSF_NO_RESPONSE;
  2252.     h->seq_number[0] = 0;
  2253.     h->seq_number[1] = 0;
  2254.     obptr += EH_SIZE;
  2255.     return True;
  2256. }
  2257. #endif /*]*/
  2258. #endif /*]*/
  2259.  
  2260. #if defined(X3270_TRACE) /*[*/
  2261. /*
  2262.  * Add IAC EOR to a buffer.
  2263.  */
  2264. void
  2265. net_add_eor(unsigned char *buf, int len)
  2266. {
  2267.     buf[len++] = IAC;
  2268.     buf[len++] = EOR;
  2269. }
  2270. #endif /*]*/
  2271.  
  2272.  
  2273. #if defined(X3270_ANSI) /*[*/
  2274. /*
  2275.  * net_sendc
  2276.  *    Send a character of user data over the network in ANSI mode.
  2277.  */
  2278. void
  2279. net_sendc(char c)
  2280. {
  2281.     if (c == '\r' && !linemode
  2282. #if defined(LOCAL_PROCESS) /*[*/
  2283.                    && !local_process
  2284. #endif /*]*/
  2285.                             ) {
  2286.         /* CR must be quoted */
  2287.         net_cookout("\r\0", 2);
  2288.     } else {
  2289.         net_cookout(&c, 1);
  2290.     }
  2291. }
  2292.  
  2293.  
  2294. /*
  2295.  * net_sends
  2296.  *    Send a null-terminated string of user data in ANSI mode.
  2297.  */
  2298. void
  2299. net_sends(const char *s)
  2300. {
  2301.     net_cookout(s, strlen(s));
  2302. }
  2303.  
  2304.  
  2305. /*
  2306.  * net_send_erase
  2307.  *    Sends the KILL character in ANSI mode.
  2308.  */
  2309. void
  2310. net_send_erase(void)
  2311. {
  2312.     net_cookout(&verase, 1);
  2313. }
  2314.  
  2315.  
  2316. /*
  2317.  * net_send_kill
  2318.  *    Sends the KILL character in ANSI mode.
  2319.  */
  2320. void
  2321. net_send_kill(void)
  2322. {
  2323.     net_cookout(&vkill, 1);
  2324. }
  2325.  
  2326.  
  2327. /*
  2328.  * net_send_werase
  2329.  *    Sends the WERASE character in ANSI mode.
  2330.  */
  2331. void
  2332. net_send_werase(void)
  2333. {
  2334.     net_cookout(&vwerase, 1);
  2335. }
  2336. #endif /*]*/
  2337.  
  2338.  
  2339. #if defined(X3270_MENUS) /*[*/
  2340. /*
  2341.  * External entry points to negotiate line or character mode.
  2342.  */
  2343. void
  2344. net_linemode(void)
  2345. {
  2346.     if (!CONNECTED)
  2347.         return;
  2348.     if (hisopts[TELOPT_ECHO]) {
  2349.         dont_opt[2] = TELOPT_ECHO;
  2350.         net_rawout(dont_opt, sizeof(dont_opt));
  2351.         vtrace_str("SENT %s %s\n", cmd(DONT), opt(TELOPT_ECHO));
  2352.     }
  2353.     if (hisopts[TELOPT_SGA]) {
  2354.         dont_opt[2] = TELOPT_SGA;
  2355.         net_rawout(dont_opt, sizeof(dont_opt));
  2356.         vtrace_str("SENT %s %s\n", cmd(DONT), opt(TELOPT_SGA));
  2357.     }
  2358. }
  2359.  
  2360. void
  2361. net_charmode(void)
  2362. {
  2363.     if (!CONNECTED)
  2364.         return;
  2365.     if (!hisopts[TELOPT_ECHO]) {
  2366.         do_opt[2] = TELOPT_ECHO;
  2367.         net_rawout(do_opt, sizeof(do_opt));
  2368.         vtrace_str("SENT %s %s\n", cmd(DO), opt(TELOPT_ECHO));
  2369.     }
  2370.     if (!hisopts[TELOPT_SGA]) {
  2371.         do_opt[2] = TELOPT_SGA;
  2372.         net_rawout(do_opt, sizeof(do_opt));
  2373.         vtrace_str("SENT %s %s\n", cmd(DO), opt(TELOPT_SGA));
  2374.     }
  2375. }
  2376. #endif /*]*/
  2377.  
  2378.  
  2379. /*
  2380.  * net_break
  2381.  *    Send telnet break, which is used to implement 3270 ATTN.
  2382.  *
  2383.  */
  2384. void
  2385. net_break(void)
  2386. {
  2387.     static unsigned char buf[] = { IAC, BREAK };
  2388.  
  2389.     /* I don't know if we should first send TELNET synch ? */
  2390.     net_rawout(buf, sizeof(buf));
  2391.     trace_str("SENT BREAK\n");
  2392. }
  2393.  
  2394. /*
  2395.  * net_interrupt
  2396.  *    Send telnet IP.
  2397.  *
  2398.  */
  2399. void
  2400. net_interrupt(void)
  2401. {
  2402.     static unsigned char buf[] = { IAC, IP };
  2403.  
  2404.     /* I don't know if we should first send TELNET synch ? */
  2405.     net_rawout(buf, sizeof(buf));
  2406.     trace_str("SENT IP\n");
  2407. }
  2408.  
  2409. /*
  2410.  * net_abort
  2411.  *    Send telnet AO.
  2412.  *
  2413.  */
  2414. #if defined(X3270_TN3270E) /*[*/
  2415. void
  2416. net_abort(void)
  2417. {
  2418.     static unsigned char buf[] = { IAC, AO };
  2419.  
  2420.     if (e_funcs & E_OPT(TN3270E_FUNC_SYSREQ)) {
  2421.         /*
  2422.          * I'm not sure yet what to do here.  Should the host respond
  2423.          * to the AO by sending us SSCP-LU data (and putting us into
  2424.          * SSCP-LU mode), or should we put ourselves in it?
  2425.          * Time, and testers, will tell.
  2426.          */
  2427.         switch (tn3270e_submode) {
  2428.         case E_NONE:
  2429.         case E_NVT:
  2430.             break;
  2431.         case E_SSCP:
  2432.             net_rawout(buf, sizeof(buf));
  2433.             trace_str("SENT AO\n");
  2434.             if (tn3270e_bound ||
  2435.                 !(e_funcs & E_OPT(TN3270E_FUNC_BIND_IMAGE))) {
  2436.                 tn3270e_submode = E_3270;
  2437.                 check_in3270();
  2438.             }
  2439.             break;
  2440.         case E_3270:
  2441.             net_rawout(buf, sizeof(buf));
  2442.             trace_str("SENT AO\n");
  2443.             tn3270e_submode = E_SSCP;
  2444.             check_in3270();
  2445.             break;
  2446.         }
  2447.     }
  2448. }
  2449. #endif /*]*/
  2450.  
  2451. #if defined(X3270_ANSI) /*[*/
  2452. /*
  2453.  * parse_ctlchar
  2454.  *    Parse an stty control-character specification.
  2455.  *    A cheap, non-complaining implementation.
  2456.  */
  2457. static char
  2458. parse_ctlchar(char *s)
  2459. {
  2460.     if (!s || !*s)
  2461.         return 0;
  2462.     if ((int) strlen(s) > 1) {
  2463.         if (*s != '^')
  2464.             return 0;
  2465.         else if (*(s+1) == '?')
  2466.             return 0177;
  2467.         else
  2468.             return *(s+1) - '@';
  2469.     } else
  2470.         return *s;
  2471. }
  2472. #endif /*]*/
  2473.  
  2474. #if defined(X3270_MENUS) || defined(C3270) /*[*/
  2475. /*
  2476.  * net_linemode_chars
  2477.  *    Report line-mode characters.
  2478.  */
  2479. struct ctl_char *
  2480. net_linemode_chars(void)
  2481. {
  2482.     static struct ctl_char c[9];
  2483.  
  2484.     c[0].name = "intr";    (void) strcpy(c[0].value, ctl_see(vintr));
  2485.     c[1].name = "quit";    (void) strcpy(c[1].value, ctl_see(vquit));
  2486.     c[2].name = "erase";    (void) strcpy(c[2].value, ctl_see(verase));
  2487.     c[3].name = "kill";    (void) strcpy(c[3].value, ctl_see(vkill));
  2488.     c[4].name = "eof";    (void) strcpy(c[4].value, ctl_see(veof));
  2489.     c[5].name = "werase";    (void) strcpy(c[5].value, ctl_see(vwerase));
  2490.     c[6].name = "rprnt";    (void) strcpy(c[6].value, ctl_see(vrprnt));
  2491.     c[7].name = "lnext";    (void) strcpy(c[7].value, ctl_see(vlnext));
  2492.     c[8].name = 0;
  2493.  
  2494.     return c;
  2495. }
  2496. #endif /*]*/
  2497.  
  2498. #if defined(X3270_TRACE) /*[*/
  2499. /*
  2500.  * Construct a string to reproduce the current TELNET options.
  2501.  * Returns a Boolean indicating whether it is necessary.
  2502.  */
  2503. Boolean
  2504. net_snap_options(void)
  2505. {
  2506.     Boolean any = False;
  2507.     int i;
  2508.     static unsigned char ttype_str[] = {
  2509.         IAC, DO, TELOPT_TTYPE,
  2510.         IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
  2511.     };
  2512.  
  2513.     if (!CONNECTED)
  2514.         return False;
  2515.  
  2516.     obptr = obuf;
  2517.  
  2518.     /* Do TTYPE first. */
  2519.     if (myopts[TELOPT_TTYPE]) {
  2520.         unsigned j;
  2521.  
  2522.         space3270out(sizeof(ttype_str));
  2523.         for (j = 0; j < sizeof(ttype_str); j++)
  2524.             *obptr++ = ttype_str[j];
  2525.     }
  2526.  
  2527.     /* Do the other options. */
  2528.     for (i = 0; i < N_OPTS; i++) {
  2529.         space3270out(6);
  2530.         if (i == TELOPT_TTYPE)
  2531.             continue;
  2532.         if (hisopts[i]) {
  2533.             *obptr++ = IAC;
  2534.             *obptr++ = WILL;
  2535.             *obptr++ = (unsigned char)i;
  2536.             any = True;
  2537.         }
  2538.         if (myopts[i]) {
  2539.             *obptr++ = IAC;
  2540.             *obptr++ = DO;
  2541.             *obptr++ = (unsigned char)i;
  2542.             any = True;
  2543.         }
  2544.     }
  2545.  
  2546. #if defined(X3270_TN3270E) /*[*/
  2547.     /* If we're in TN3270E mode, snap the subnegotations as well. */
  2548.     if (myopts[TELOPT_TN3270E]) {
  2549.         any = True;
  2550.  
  2551.         space3270out(5 +
  2552.             ((connected_type != CN) ? strlen(connected_type) : 0) +
  2553.             ((connected_lu != CN) ? + strlen(connected_lu) : 0) +
  2554.             2);
  2555.         *obptr++ = IAC;
  2556.         *obptr++ = SB;
  2557.         *obptr++ = TELOPT_TN3270E;
  2558.         *obptr++ = TN3270E_OP_DEVICE_TYPE;
  2559.         *obptr++ = TN3270E_OP_IS;
  2560.         if (connected_type != CN) {
  2561.             (void) memcpy(obptr, connected_type,
  2562.                     strlen(connected_type));
  2563.             obptr += strlen(connected_type);
  2564.         }
  2565.         if (connected_lu != CN) {
  2566.             *obptr++ = TN3270E_OP_CONNECT;
  2567.             (void) memcpy(obptr, connected_lu,
  2568.                     strlen(connected_lu));
  2569.             obptr += strlen(connected_lu);
  2570.         }
  2571.         *obptr++ = IAC;
  2572.         *obptr++ = SE;
  2573.  
  2574.         space3270out(38);
  2575.         (void) memcpy(obptr, functions_req, 4);
  2576.         obptr += 4;
  2577.         *obptr++ = TN3270E_OP_IS;
  2578.         for (i = 0; i < 32; i++) {
  2579.             if (e_funcs & E_OPT(i))
  2580.                 *obptr++ = i;
  2581.         }
  2582.         *obptr++ = IAC;
  2583.         *obptr++ = SE;
  2584.  
  2585.         if (tn3270e_bound) {
  2586.             tn3270e_header *h;
  2587.  
  2588.             space3270out(EH_SIZE + 3);
  2589.             h = (tn3270e_header *)obptr;
  2590.             h->data_type = TN3270E_DT_BIND_IMAGE;
  2591.             h->request_flag = 0;
  2592.             h->response_flag = 0;
  2593.             h->seq_number[0] = 0;
  2594.             h->seq_number[1] = 0;
  2595.             obptr += EH_SIZE;
  2596.             *obptr++ = 1; /* dummy */
  2597.             *obptr++ = IAC;
  2598.             *obptr++ = EOR;
  2599.         }
  2600.     }
  2601. #endif /*]*/
  2602.     return any;
  2603. }
  2604. #endif /*]*/
  2605.  
  2606. /*
  2607.  * Set blocking/non-blocking mode on the socket.  On error, pops up an error
  2608.  * message, but does not close the socket.
  2609.  */
  2610. static int
  2611. non_blocking(Boolean on)
  2612. {
  2613. #if !defined(BLOCKING_CONNECT_ONLY) /*[*/
  2614. # if defined(FIONBIO) /*[*/
  2615.     int i = on ? 1 : 0;
  2616.  
  2617.     if (ioctl(sock, FIONBIO, &i) < 0) {
  2618.         popup_an_errno(errno, "ioctl(FIONBIO)");
  2619.         return -1;
  2620.     }
  2621. # else /*][*/
  2622.     int f;
  2623.  
  2624.     if ((f = fcntl(sock, F_GETFL, 0)) == -1) {
  2625.         popup_an_errno(errno, "fcntl(F_GETFL)");
  2626.         return -1;
  2627.     }
  2628.     if (on)
  2629.         f |= O_NDELAY;
  2630.     else
  2631.         f &= ~O_NDELAY;
  2632.     if (fcntl(sock, F_SETFL, f) < 0) {
  2633.         popup_an_errno(errno, "fcntl(F_SETFL)");
  2634.         return -1;
  2635.     }
  2636. # endif /*]*/
  2637. #endif /*]*/
  2638.     return 0;
  2639. }
  2640.  
  2641. #if defined(X3270_TRACE) /*[*/
  2642.  
  2643. static void
  2644. trace_str(const char *s)
  2645. {
  2646.     if (!toggled(DS_TRACE))
  2647.         return;
  2648.     (void) fprintf(tracef, "%s", s);
  2649. }
  2650.  
  2651. static void
  2652. vtrace_str(const char *fmt, ...)
  2653. {
  2654.     static char trace_msg[256];
  2655.     va_list args;
  2656.  
  2657.     if (!toggled(DS_TRACE))
  2658.         return;
  2659.  
  2660.     va_start(args, fmt);
  2661.     (void) vsprintf(trace_msg, fmt, args);
  2662.     trace_str(trace_msg);
  2663. }
  2664.  
  2665. #endif /*]*/
  2666.